# -*- coding: utf-8 -*-
# @author: HRUN

import os
import json
import time
import logging
from datetime import datetime
from django.utils import timezone
from typing import Dict, List, Optional, Any
from dataclasses import dataclass

import django
# 设置Django环境
# 统一通过ENV变量判断
if "DJANGO_SETTINGS_MODULE" not in os.environ:
    env = os.environ.get("ENV")
    if env == "production":
        settings_module = "primaryApp.settings.pro"
    else:
        settings_module = "primaryApp.settings.dev"
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", settings_module)
django.setup()

from performance.models import TaskReport, PerformanceTask
from projects.models import TestEnv

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


@dataclass
class PerformanceMetrics:
    """性能指标数据类"""
    total_requests: int = 0
    failed_requests: int = 0
    success_requests: int = 0
    avg_response_time: float = 0.0
    min_response_time: float = 0.0
    max_response_time: float = 0.0
    median_response_time: float = 0.0
    p90_response_time: float = 0.0
    p95_response_time: float = 0.0
    p99_response_time: float = 0.0
    requests_per_second: float = 0.0
    failures_per_second: float = 0.0
    avg_content_length: float = 0.0
    error_rate: float = 0.0
    # 用户数相关指标
    current_users: int = 0
    max_users: int = 0
    avg_users: float = 0.0
    # 接口统计数据
    interface_stats: dict = None


class LocustResultParser:
    """Locust结果解析器"""
    
    def __init__(self):
        self.stats_history = []
        self.failure_history = []
        
    def parse_stats_line(self, line: str) -> Optional[Dict]:
        """解析统计信息行"""
        try:
            if line.startswith('[') and '"stats"' in line:
                # 解析JSON格式的统计信息
                data = json.loads(line.split('] ')[1])
                return data
        except (json.JSONDecodeError, IndexError) as e:
            logger.debug(f"解析统计行失败: {e}")
        return None
    
    def parse_failure_line(self, line: str) -> Optional[Dict]:
        """解析失败信息行"""
        try:
            if line.startswith('[') and '"failures"' in line:
                data = json.loads(line.split('] ')[1])
                return data
        except (json.JSONDecodeError, IndexError) as e:
            logger.debug(f"解析失败行失败: {e}")
        return None
    
    def calculate_metrics(self, stats_data: List[Dict]) -> PerformanceMetrics:
        """计算性能指标"""
        if not stats_data:
            return PerformanceMetrics()
        
        # 获取最新的统计数据
        latest_stats = stats_data[-1] if stats_data else {}
        stats = latest_stats.get('stats', [])
        
        # 计算汇总指标
        total_requests = 0
        total_failures = 0
        total_response_time = 0
        min_response = float('inf')
        max_response = 0
        response_times = []
        
        for stat in stats:
            if stat.get('name') != 'Aggregated':  # 跳过汇总行
                requests = stat.get('num_requests', 0)
                failures = stat.get('num_failures', 0)
                avg_response = stat.get('avg_response_time', 0)
                min_resp = stat.get('min_response_time', 0)
                max_resp = stat.get('max_response_time', 0)
                
                total_requests += requests
                total_failures += failures
                total_response_time += avg_response * requests
                
                if min_resp < min_response and min_resp > 0:
                    min_response = min_resp
                if max_resp > max_response:
                    max_response = max_resp
                
                # 收集响应时间数据用于百分位计算
                response_times.extend([avg_response] * requests)
        
        # 计算指标
        success_requests = total_requests - total_failures
        avg_response_time = total_response_time / total_requests if total_requests > 0 else 0
        error_rate = (total_failures / total_requests * 100) if total_requests > 0 else 0
        
        # 计算百分位数（简化计算）
        response_times.sort()
        length = len(response_times)
        
        p50 = response_times[int(length * 0.5)] if length > 0 else 0
        p90 = response_times[int(length * 0.9)] if length > 0 else 0
        p95 = response_times[int(length * 0.95)] if length > 0 else 0
        p99 = response_times[int(length * 0.99)] if length > 0 else 0
        
        return PerformanceMetrics(
            total_requests=total_requests,
            failed_requests=total_failures,
            success_requests=success_requests,
            avg_response_time=avg_response_time,
            min_response_time=min_response if min_response != float('inf') else 0,
            max_response_time=max_response,
            median_response_time=p50,
            p90_response_time=p90,
            p95_response_time=p95,
            p99_response_time=p99,
            error_rate=error_rate
        )


class TaskResultCollector:
    """任务结果收集器"""
    
    def __init__(self, task_id: int, env_id: Optional[int] = None, gui_url: Optional[str] = None):
        self.task_id = task_id
        self.env_id = env_id
        self.parser = LocustResultParser()
        self.report = None
        self.start_time = None
        self.end_time = None
        # 用户数统计
        self.users_history = []  # 存储用户数历史数据
        self.gui_url = gui_url
        
    def create_report(self, report_name: str, executor: str = 'system') -> TaskReport:
        """创建测试报告"""
        try:
            task = PerformanceTask.objects.get(id=self.task_id)
            env = TestEnv.objects.get(id=self.env_id) if self.env_id else None
            
            # 生成报告名称
            if not report_name:
                timestamp = datetime.now().strftime('%Y/%d/%m %H:%M:%S')
                report_name = f"{task.taskName}报告_{timestamp}"

            
            self.report = TaskReport.objects.create(
                task=task,
                env=env,
                reportName=report_name,
                reportStatus='1',  # 执行中
                executor=executor,
                startTime=timezone.now(),
                creator=executor
            )
            
            logger.info(f"创建测试报告: {report_name} (ID: {self.report.id})")
            return self.report
            
        except Exception as e:
            logger.error(f"创建报告失败: {e}")
            raise
    
    def update_report_status(self, status: str, metrics: Optional[PerformanceMetrics] = None):
        """更新报告状态和指标"""
        if not self.report:
            logger.warning("报告不存在，无法更新状态")
            return
        
        try:
            self.report.reportStatus = status
            self.report.endTime = timezone.now()
            
            if metrics:
                # 更新性能指标
                self.report.totalRequests = metrics.total_requests
                self.report.successRequests = metrics.success_requests
                self.report.failedRequests = metrics.failed_requests
                self.report.avgResponseTime = metrics.avg_response_time
                self.report.minResponseTime = metrics.min_response_time
                self.report.maxResponseTime = metrics.max_response_time
                self.report.p50ResponseTime = metrics.median_response_time
                self.report.p90ResponseTime = metrics.p90_response_time
                self.report.p95ResponseTime = metrics.p95_response_time
                self.report.p99ResponseTime = metrics.p99_response_time
                self.report.errorRate = metrics.error_rate
                self.report.failuresPerSecond = metrics.failures_per_second
                
                # 更新用户数指标
                if metrics.max_users > 0:
                    self.report.maxUsers = metrics.max_users
                if metrics.avg_users > 0:
                    self.report.avgUsers = metrics.avg_users
                
                # 计算TPS（各接口平均值之和）
                if self.report.startTime and self.report.endTime:
                    duration = (self.report.endTime - self.report.startTime).total_seconds()
                    self.report.duration = int(duration)
                    
                    # 计算各接口的TPS并求和（使用current_rps数据保持与前端一致）
                    total_interface_tps = 0
                    if hasattr(metrics, 'interface_stats') and metrics.interface_stats:
                        for interface_key, interface_data in metrics.interface_stats.items():
                            # 优先使用current_rps（实时RPS）作为TPS，与前端逻辑保持一致
                            interface_tps = interface_data.get('current_rps', 0)
                            if interface_tps == 0:
                                # 如果没有current_rps，使用平均值计算作为后备
                                interface_requests = interface_data.get('total_requests', 0)
                                interface_tps = interface_requests / duration if duration > 0 else 0
                            total_interface_tps += interface_tps
                    
                    # 如果没有接口统计数据，使用总体数据作为后备
                    self.report.avgTps = total_interface_tps if total_interface_tps > 0 else (metrics.total_requests / duration if duration > 0 else 0)
                elif metrics.requests_per_second > 0:
                    # 如果有RPS数据，直接使用
                    self.report.avgTps = metrics.requests_per_second
            
            # 如果报告状态是完成或失败，获取最新的CPU和内存值
            if status in ['0', '99'] and self.report.reportResult:
                try:
                    # 从报告结果中提取最新的系统资源数据
                    report_data = json.loads(self.report.reportResult)
                    stats_history = report_data.get('stats_history', [])
                    
                    # 查找最新的系统资源数据
                    latest_system_info = None
                    for stat in reversed(stats_history):
                        if 'system_info' in stat:
                            latest_system_info = stat['system_info']
                            break
                    
                    # 使用最新的系统资源数据
                    if latest_system_info:
                        if 'cpu' in latest_system_info and 'percent' in latest_system_info['cpu']:
                            self.report.avgCpu = latest_system_info['cpu']['percent']
                            logger.info(f"记录最新CPU使用率: {self.report.avgCpu}%")
                        
                        if 'memory' in latest_system_info and 'percent' in latest_system_info['memory']:
                            self.report.avgMemory = latest_system_info['memory']['percent']
                            logger.info(f"记录最新内存使用率: {self.report.avgMemory}%")
                
                except (json.JSONDecodeError, KeyError) as e:
                    logger.error(f"解析报告结果数据失败: {e}")
                except Exception as e:
                    logger.error(f"获取最新CPU和内存使用率失败: {e}")
            
            self.report.save()
            # logger.info(f"更新报告状态: {status} (ID: {self.report.id})")
            
        except Exception as e:
            logger.error(f"更新报告状态失败: {e}")
    
    def collect_from_log_file(self, log_file_path: str) -> PerformanceMetrics:
        """从日志文件收集结果"""
        stats_data = []
        failure_data = []
        
        try:
            with open(log_file_path, 'r', encoding='utf-8') as f:
                for line in f:
                    # 解析统计信息
                    stats = self.parser.parse_stats_line(line)
                    if stats:
                        stats_data.append(stats)
                    
                    # 解析失败信息
                    failure = self.parser.parse_failure_line(line)
                    if failure:
                        failure_data.append(failure)
            
            # 计算指标
            metrics = self.parser.calculate_metrics(stats_data)
            
            # 保存详细数据到报告
            if self.report:
                detailed_result = {
                    'stats_history': stats_data[-10:],  # 保存最后10次统计
                    'failure_summary': failure_data[-10:],  # 保存最后10次失败
                    'collection_time': timezone.now().isoformat()
                }
                self.report.reportResult = json.dumps(detailed_result, ensure_ascii=False)
                self.report.save()
            
            return metrics
            
        except FileNotFoundError:
            logger.warning(f"日志文件不存在: {log_file_path}")
            return PerformanceMetrics()
        except Exception as e:
            logger.error(f"收集日志文件结果失败: {e}")
            return PerformanceMetrics()
    
    def collect_from_locust_stats(self, stats_dict: Dict) -> PerformanceMetrics:
        """
        兼容单机和分布式：
        - 分布式模式下优先用detailed_stats聚合所有接口明细（不含Aggregated）
        - 单机模式保持原有逻辑
        """
        try:
            # 优先用detailed_stats聚合（分布式模式）
            detailed_stats = stats_dict.get('detailed_stats')
            if detailed_stats and isinstance(detailed_stats, dict) and detailed_stats:
                # 只聚合非Aggregated接口
                stats_list = [v for k, v in detailed_stats.items() if k != 'Aggregated']
                metrics = LocustResultParser().calculate_metrics([{'stats': stats_list}])
            else:
                # 单机模式兼容原有逻辑
                metrics = LocustResultParser().calculate_metrics([stats_dict])

            # 保存详细统计数据到报告
            if self.report:
                total_stats = stats_dict.get('total', {})
                detailed_result = {
                    'total': total_stats,
                    'detailed_stats': detailed_stats or {},
                    'timestamp': timezone.now().isoformat(),
                    'stats_history': [stats_dict] if 'stats_history' not in stats_dict else stats_dict.get('stats_history', []),
                    'gui_url': self.gui_url
                }
                # 如果已有报告结果，尝试合并历史数据
                if self.report.reportResult:
                    try:
                        existing_result = json.loads(self.report.reportResult)
                        if 'stats_history' in existing_result:
                            # 合并历史数据，保持最新100条
                            existing_history = existing_result.get('stats_history', [])
                            new_history = existing_history + [stats_dict]
                            detailed_result['stats_history'] = new_history[-100:]  # 保持最新100条
                    except (json.JSONDecodeError, KeyError):
                        pass
                self.report.reportResult = json.dumps(detailed_result, ensure_ascii=False)
                self.report.save()
            return metrics
        except Exception as e:
            logger.error(f"从Locust统计数据收集失败: {e}")
            return PerformanceMetrics()


def create_and_monitor_report(task_id: int, env_id: Optional[int] = None, 
                             report_name: Optional[str] = None, 
                             executor: str = 'system') -> TaskReport:
    """创建报告并开始监控"""
    collector = TaskResultCollector(task_id, env_id)
    report = collector.create_report(report_name or '', executor)
    return report


def update_report_with_results(report_id: int, results_data: Dict, gui_url: str = None) -> bool:
    """使用结果数据更新报告"""
    try:
        # 直接使用同步方式
        return _update_report_with_results_sync(report_id, results_data, gui_url)
    except Exception as e:
        logger.error(f"更新报告失败: {e}")
        return False


def _update_report_with_results_sync(report_id: int, results_data: Dict, gui_url: str = None) -> bool:
    """同步方式更新报告结果"""
    try:
        report = TaskReport.objects.get(id=report_id)
        
        # 如果报告已经完成，不要更新
        if report.reportStatus in ['0', '99']:
            logger.debug(f"报告 {report.reportName} 已完成，跳过更新")
            return True
        
        # 创建临时收集器
        collector = TaskResultCollector(report.task.id, report.env.id if report.env else None, gui_url)
        collector.report = report
        
        # 从结果数据计算指标
        metrics = collector.collect_from_locust_stats(results_data)
        
        # 保持运行状态，不改变状态
        # 只更新指标数据
        collector.update_report_status(report.reportStatus, metrics)
        
        logger.debug(f"更新报告 {report.reportName} 的实时数据")
        return True
        
    except TaskReport.DoesNotExist:
        logger.error(f"报告不存在: {report_id}")
        return False
    except Exception as e:
        logger.error(f"更新报告失败: {e}")
        return False


def finalize_report(report_id: int, success: bool = True, 
                   final_stats: Optional[Dict] = None) -> bool:
    """完成报告"""
    try:
        # 直接使用同步方式
        return _finalize_report_sync(report_id, success, final_stats)
    except Exception as e:
        logger.error(f"完成报告失败: {e}")
        return False


def _finalize_report_sync(report_id: int, success: bool = True, 
                         final_stats: Optional[Dict] = None) -> bool:
    """同步方式完成报告"""
    try:
        logger.info(f"开始完成报告: report_id={report_id}, success={success}")
        
        report = TaskReport.objects.get(id=report_id)
        
        # 如果报告已经是完成状态，不要重复处理
        if report.reportStatus in ['0', '99']:
            logger.warning(f"报告 {report.reportName} 已经完成，跳过重复处理")
            return True
        
        # 当on_test_stop被调用时，说明测试已经结束了
        # 我们应该相信Locust的判断，直接标记为完成
        
        # 判断测试是否成功
        actual_success = success
        
        if final_stats:
            total_stats = final_stats.get('total', {})
            total_requests = total_stats.get('num_requests', 0)
            
            logger.info(f"统计数据: total_requests={total_requests}")
            
            # 如果没有请求产生，可能是配置错误或测试异常
            if total_requests == 0:
                actual_success = False
                logger.warning(f"测试结束但没有产生任何请求")
        else:
            # 没有统计数据，可能是异常终止
            actual_success = False
            logger.warning(f"测试终止但没有统计数据")
        
        # 设置最终状态
        status = '0' if actual_success else '99'
        report.reportStatus = status
        report.endTime = timezone.now()
        
        # 同时更新任务状态
        task = report.task
        task.status = status  # 与报告状态保持一致：'0'表示执行完成，'99'表示执行失败
        task.save()
        
        logger.info(f"准备更新报告状态为: {status}, 任务状态为: {status}")
        
        if final_stats:
            try:
                # 确保final_stats包含系统资源信息
                if 'system_info' not in final_stats:
                    # 尝试从reportResult中获取最新的系统资源信息
                    try:
                        if report.reportResult:
                            report_data = json.loads(report.reportResult)
                            stats_history = report_data.get('stats_history', [])
                            if stats_history:
                                # 获取最新的系统资源信息
                                for stat in reversed(stats_history):
                                    if 'system_info' in stat:
                                        final_stats['system_info'] = stat['system_info']
                                        break
                    except Exception as e:
                        logger.error(f"获取系统资源信息失败: {e}")
                
                # 更新最终统计信息
                collector = TaskResultCollector(report.task.id)
                collector.report = report
                metrics = collector.collect_from_locust_stats(final_stats)
                collector.update_report_status(status, metrics)
                logger.info(f"已通过collector更新报告状态")
            except AttributeError as ae:
                logger.error(f"属性错误: {ae}")
                # 如果collector失败，直接保存报告
                report.save()
                logger.info(f"因属性错误，已直接保存报告状态")
            except Exception as ce:
                logger.error(f"更新统计信息失败: {ce}")
                # 如果collector失败，直接保存报告
                report.save()
                logger.info(f"因更新错误，已直接保存报告状态")
        else:
            # 即使没有统计数据，也尝试获取最新的CPU和内存值
            try:
                if report.reportResult:
                    collector = TaskResultCollector(report.task.id)
                    collector.report = report
                    # 尝试更新报告状态
                    collector.update_report_status(status)
            except Exception as e:
                logger.error(f"更新报告状态失败: {e}")
                # 如果失败，直接保存报告
                report.save()
        
        # 停止对应的系统监控
        try:
            from performanceengine.systemMonitor import stop_system_monitoring
            stop_system_monitoring(report_id)
            logger.info(f"已停止报告 {report_id} 的系统监控")
        except Exception as e:
            logger.error(f"停止系统监控失败: {e}")
        
        return True
        
    except Exception as e:
        logger.error(f"完成报告失败: {e}")
        return False


# 示例使用
if __name__ == '__main__':
    # 测试创建报告
    # report = create_and_monitor_report(1, 1, "测试报告", "admin")
    # print(f"创建报告: {report.id}")
    
    # 测试更新报告
    # test_results = {
    #     'total': {
    #         'num_requests': 1000,
    #         'num_failures': 50,
    #         'avg_response_time': 245.5,
    #         'min_response_time': 100,
    #         'max_response_time': 500,
    #         'current_rps': 50.2
    #     },
    #     'success': True
    # }
    # update_report_with_results(report.id, test_results)
    pass